from . import passport_blue
from flask import request, jsonify, current_app, make_response, session
# 导入自定义状态码
from info.utils.response_code import RET
# 导入capcha生成图片验证码
from info.utils.captcha.captcha import captcha
# 导入redis实例
from info import redis_store, models
# 导入redis过期时间,数据库对象
from info import constants, db
import re
# 云通讯发送短信
from info.libs.yuntongxun import sms
import random

from info.models import User
from datetime import datetime


@passport_blue.route('/image_code')
def generate_image_code():
    """
    生成图片验证码
    前端生成uuid发给后端
    获取参数,校验参数,业务处理,返回数据
    1.获取参数：args查询字符串
    2.校验参数是否存在,不存在则报错给前端
    3.调用capcha生成图片验证码：name,text,image
    4.redis存储验证码内容
    5.返回图片,response = make_response(image)   return  response
    6.修改相应数据类型：image/jpg
    :return:
    """
    # 获取uuid作为后缀保存到redis数据库
    image_code_id = request.args.get('imageCodeId')
    if not image_code_id:
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')
    # 参数存在,调用capcha生成图片验证码
    name, text, image = captcha.generate_captcha()
    print('验证码内容：', text)
    try:
        # 创建StrictRedis对象，与redis服务器建⽴连接
        sr = redis_store
        sr.setex('image_code' + image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='保存图片验证码失败')
    else:
        response = make_response(image)
        response.headers['Content_Type'] = 'image/jpg'
        return response


@passport_blue.route('/sms_send', methods=['POST'])
def sms_send():
    """
    需要3个参数：手机号,输入的图片验证码,uuid
    1.获取参数(json数据)：mobile, image_code,image_code_id
    2.判断参数是否存在
    3.校验手机号.图片验证码和redis的数据比较(先删除再比较),判断是否过期,过期返回前端说明过期
    4.一旦获取就删除redis中的对应数据,因为只允许用户get一次
    5.生成短信内容(6位随机数)
    6.在redis数据库存储验证码随机数,发送短信,保存发送结果判断是否发送成功。不成功告诉前端
    6.返回数据
    :return:
    """
    # 1.获取参数(json数据)：mobile, image_code,image_code_id
    mobile = request.json.get('mobile')
    image_code = request.json.get('imageCode')
    print('用户输入为：', image_code)  # ***********************************
    image_code_id = request.json.get('imageCodeId')
    if not all([mobile, image_code_id, image_code]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')
    # 判断参数合法？
    result = re.match(r'^1[3456789]\d{9}$', mobile)
    if not result:
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误')
    # 判断redis存储的数据和前端的发送的是否一致
    try:
        # 创建StrictRedis对象，与redis服务器建⽴连接
        sr = redis_store
        real_text = sr.get('image_code' + image_code_id)
        print('数据库中为：', real_text)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='验证码查询失败')
    if not real_text:
        return jsonify(errno=RET.NODATA, errmsg='验证码过期')
    # 删除验证码
    try:
        sr.delete('image_code' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
    if not (real_text.lower() == image_code.lower()):
        return jsonify(errno=RET.DATAERR, errmsg='用户输入错误')

    # 判断手机是否已经存在
    try:
        mobile_exsist = models.User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询失败')
    else:
        if mobile_exsist:
            return jsonify(errno=RET.DATAEXIST, errmsg='该手机已经存在')
    # 输入正确,调用接口发送短信
    sms_code = '%06d' % random.randint(0, 999999)
    print('下面发送短信,验证码：', sms_code)
    # 将数据存在redis
    try:
        # 创建StrictRedis对象，与redis服务器建⽴连接
        sr = redis_store
        sr.setex('sms_code' + mobile, constants.IMAGE_CODE_REDIS_EXPIRES, sms_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='短信验证码存储失败')
    try:
        ccp = sms.CCP()
        # 调用云通讯的模板方法，发送短信
        print('手机号：', mobile)
        result_sms = ccp.send_template_sms(mobile, ['臭佳,吃啥呀？' + sms_code, 5], 1)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='发送短信异常')
    if result_sms == 0:
        return jsonify(errno=RET.OK, errmsg='发送成功')
    else:
        return jsonify(errno=RET.THIRDERR, errmsg='发送短信异常')


@passport_blue.route('/register', methods=['POST'])
def register():
    """
    1.获取参数：mobile,smscode,password
    2.检查参数完整性
    3.校验手机号：防止获取验证码以后修改手机号
    4.从redis中获取验证码(判断是否获取到),之后比较
    5.不一样则返回：可以获取多次；一样则删除
    6.查询mysql数据库,判断是否存在
    7.构造模型类对象,保存用户数据
    8.提交数据到数据库
    9.将用户信息缓存到redis(便于数据的访问,跳转页面是要查询数据库,redis速度快)
    10.返回结果
    :return:
    """
    # 获取参数,data = request.json;request.get_json()
    mobile = request.json.get('mobile')
    sms_code = request.json.get('sms_code')
    password = request.json.get('password')
    # 检查参数的完整性
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    # 检查手机号的格式
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误')
    # 获取本地存储的真实短信验证码
    try:
        real_sms_code = redis_store.get('sms_code' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据失败')
    # 判断获取结果
    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg='短信验证码已过期')
    # 比较短信验证码是否正确
    if real_sms_code != str(sms_code):
        return jsonify(errno=RET.DATAERR, errmsg='短信验证码错误')
    # 删除已经比较过的短信验证码
    try:
        redis_store.delete('sms_code' + mobile)
    except Exception as e:
        current_app.logger.error(e)
    # 判断手机号是否已注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据失败')
    else:
        if user is not None:
            return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册')
    # 构造模型类对象
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    # password属性封装了密码加密的方法，实现了密码的加密存储
    user.password = password
    # 提交数据到mysql数据库中
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 如果提交数据发生异常，需要进行回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='保存数据失败')
    # 把用户信息缓存到redis数据库中
    # redis_store.setex('user_id')  ------->会覆盖
    session['user_id'] = user.id
    session['mobile'] = mobile
    session['nick_name'] = mobile
    # 返回结果
    return jsonify(errno=RET.OK, errmsg='注册成功')


@passport_blue.route('/login', methods=['POST'])
def login():
    """
    1.获取参数：mobile,password
    2.校验参数
    3.验证手机号
    4.根据手机号查询,判断用户是否已经注册
    5.判断获取结果：注册了直接登录,没注册提醒注册
    6.调用模型类方法校验密码
    7.记录登录时间(统计月活,日活个数):last_login    datetime.now()
    8.提交时间数据到mysql数据库
    9.缓存用户信息session['nick_name']= User,nick_name
    10.返回结果
    :return:
    """
    mobile = request.json.get('mobile')
    password = request.json.get('password')
    # 检查参数的完整性
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    # 检查手机号的格式
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误')
    # 根据手机号查询,判断用户是否已经注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询失败')
    # 判断获取结果：注册了直接登录,没注册提醒注册
    # if not user:
    #     return jsonify(errno=RET.NODATA, errmsg='用户未注册')
    # # 检查密码正确性
    # if not user.check_password(password):
    #     return jsonify(errno=RET.PWDERR, errmsg='密码错误')
    if user is None or not user.check_password(password):
        return jsonify(errno=RET.PWDERR, errmsg='用户名或者密码错误')  # 这样写对用户更好
    # 保存用户的登录时间
    user.last_login = datetime.now()
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='数据库错误')
    # 缓存用户信息
    session['user_id'] = user.id
    session['mobile'] = mobile
    session['nick_name'] = user.nick_name
    # 返回结果
    return jsonify(errno=RET.OK, errmsg='登陆成功')


@passport_blue.route('/logout', methods=['GET'])
def logout():
    """
    如果是restful设计风格, 并且项目是前后端分离的,请求方法必须是delete   前端使用ajax写delete请求
    1.将缓存在redis数据库的用户信息删除
    session.clear():将redis清空----->不建议使用
    :return:
    """
    session.pop('user_id', None)
    session.pop('mobile', None)
    session.pop('nick_name', None)
    return jsonify(errno=RET.OK, errmsg='退出成功')